Objectives of the
Interactive Plot
The shooting data set is neither a population nor a random sample
from a population in Philadelphia. It is a set of public records of
shootings in the neighborhoods of Philadelphia for the past 10 years.
This data contains some geographical information such as district
information, block/location, longitude, latitude etc. The main
objectives are:
- Shooting trend by year
- Age density distribution
- Bubble plot on the map
- Table of total shootings categorized under Race, Sex and Age from
2015 t0 2024
- Bar plot of shooting counts by Race
- Map showing shooting counts for each district
Total Shootings for
Districts
Shooting data was aggregated by district to include fatal, nonfatal
and total shootings for all districts. This information was illustrated
on a map and shown below. The circle size is proportional to the number
of shootings in a district. District 25 had the largest fatal and
nonfatal shootings.
shooting_data$lng = shooting_data$point_x
shooting_data$lat = shooting_data$point_y
dist.CrimeTable = table(shooting_data$fatal, shooting_data$dist)
distLon = aggregate(shooting_data$lng, by=list(shooting_data$dist), FUN=mean)
distLat = aggregate(shooting_data$lat, by=list(shooting_data$dist), FUN=mean)
distLonLat = merge(distLon, distLat, by = "Group.1")
names(distLonLat) = c("district", "lng", "lat")
distCrime = data.frame(district=as.numeric(names(table(shooting_data$dist))),
fatal = table(shooting_data$fatal, shooting_data$dist)[2,],
nonfatal = table(shooting_data$fatal, shooting_data$dist)[1,],
total.crime = table(shooting_data$dist)
)
distCrime = distCrime[, c("district", "fatal", "nonfatal", "total.crime.Freq")]
colnames(distCrime) = c("district", "fatal", "nonfatal", "total.crime")
distCrime = merge(distLonLat, distCrime, by = "district")
title2 <- tags$div(HTML('<font color = "darkred" size =5><b>Shootings in Philadelphia Districts</b></font>'))
pal0 <- colorNumeric(palette = viridis(256, option = "B"), domain = range(distCrime$total.crime))
distfig <- leaflet() %>%
setView(lng=-75.1527, lat=39.9707, zoom = 11) %>%
addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
## plot the neighborhood boundary of Philly
addPolygons(data = phillyNeighbor,
color = 'lightgreen',
weight = 1) %>%
addControl(title2, position = "topright", className="map-title")%>%
##
addCircleMarkers(data = distCrime,
radius = ~((total.crime)^(1/3)),
color = ~pal0(total.crime),
stroke = FALSE,
fillOpacity = 0.5,
popup = ~paste('District:',district,
'<br>Total Crime:', total.crime,
'<br>Fatal Crime:', fatal,
'<br>Nonfatal Crime:', nonfatal))
distfig
plot.theme <- function() {
theme(
plot.title = element_text(face = "bold",
size = 12,
family = "sans",
color = "#009E73",
hjust = 0.5),
# add border 1)
panel.border = element_rect(colour = "#009E73",
fill = NA,
linetype = 2),
# color background 2)
# panel.background = element_rect(fill = "#F0E442"),
# modify grid 3)
panel.grid.major.x = element_line(colour = "#56B4E9",
linetype = 3,
size = 0.5),
panel.grid.minor.x = element_blank(),
panel.grid.major.y = element_line(colour = "#56B4E9",
linetype = 3,
size = 0.5),
panel.grid.minor.y = element_blank(),
axis.text = element_text(colour = "#56B4E9",
face = "italic",
family = "Times New Roman"),
axis.title = element_text(colour = "#0072B2",
family = "Times New Roman"),
axis.ticks = element_line(colour = "#56B4E9"))
}
Shooting Trend by
Year
The plot below shows the shooting trend from 2015 to 2024. There was
a sharp increase in the number of shootings from 2019 to 2020. This
increase was maintained all through till 2022 and then was followed by a
sharp decline in 2023. The increase seen from 2020 to 2022 can be
related to the coronavirus period.
# trend
yearCrime = data.frame(year=as.numeric(names(table(shooting_data$year))),
fatal = table(shooting_data$fatal, shooting_data$year))
yearCrime = yearCrime[,-1]
colnames(yearCrime) = c("fatal", "year", "total")
A1 <- ggplot(data = yearCrime, aes(x = year, y = total, group = fatal, col = fatal)) +
geom_line() +
geom_point() +
geom_text(aes(label = total), size = 3) +
scale_color_manual(values=c("#D55E00", "#0072B2"), labels=c("Nonfatal", "Fatal"))+
plot.theme()+
labs(title = "Shooting Counts by Year",
x = "Year",
y = "Shooting Counts")
A1
Age Distribution
The density plot below shows the distribution of the ages of
individuals who were shot. The most common age for shooting victims was
28.
## 1. age distribution
# Basic density plot in ggplot2
shooting_data$age = as.numeric(shooting_data$age)
fatalAge = ggplot(data = shooting_data, aes(x = age, fill = as.factor(fatal)) )+
geom_density(alpha = 0.6) +
scale_fill_manual(values = c("#CC79A7", "#72D8FF"), labels=c("Nonfatal", "Fatal"))+
labs(fill = "Fatal",
title = "Distribution of Age") +
plot.theme()
fatalAge
Race
Distribution
A bar plot was used to illustrate the total shootings by race. Four
different racial groups were represented in the dataset. They are Asian,
Black, Unknown and White. The group with the highest number of shooting
victims were Blacks with over 12000 records in 10 years.
A2 <- ggplot(data = shooting_data, aes(x = race)) +
geom_bar(color = "#56B4E9", fill = "yellow")+
labs(x = "Race",
y = "Total Shootings",
title = "Plot of Total Shootings By Race") +
scale_x_discrete(labels = c("A" = "Asian", "B" = "Black", "U" = "Unknown", "W" = "White")) +
plot.theme()
A2
Summary Table
A table summarizing total shootings by sex, race, age is shown below.
The average age of shooting victims was 28 in the earlier years and then
increased to 31 later. Black males are more likely to be victims of
shooting crimes than other groups.
dt = data.frame(year=as.numeric(names(table(shooting_data$year))),
fatal = table(shooting_data$fatal, shooting_data$year)[2,],
nonfatal = table(shooting_data$fatal, shooting_data$year)[1,],
total.crime = table(shooting_data$year),
Black = table(shooting_data$race, shooting_data$year)[2,],
Males = table(shooting_data$sex, shooting_data$year)[2,],
Females = table(shooting_data$sex, shooting_data$year)[1,],
age = signif(tapply(shooting_data$age, shooting_data$year, mean), digits = 2)
)
dt = dt[,-c(1,4,5)]
colnames(dt) = c("Fatal", "Nonfatal", "Black", "Males", "Females", "Age")
A3 <- DT::datatable(dt, fillContainer = FALSE, options = list(pageLength = 5))
A3
Animated Plot of
Shootings By Year
which_state <- "pennsylvania"
county_info <- map_data("county", region=which_state)
philly_info <- county_info[county_info$subregion == "philadelphia",]
base_map <- ggplot(data = philly_info, mapping = aes(x = long, y = lat, group = group)) +
geom_polygon(color = "#009E73", fill = "lightyellow") +
coord_quickmap() +
theme_void()
map_with_data <- base_map +
geom_point(data = shooting_data, aes(x = lng, y = lat, color = factor(fatal), fill = factor(fatal), group=year), size = 2, alpha = 0.5) +
scale_shape_manual(values = c(21, 24)) +
scale_color_manual(values = c("#0072B2", "#D55E00"))
map_with_animation <- map_with_data +
transition_time(year) +
ggtitle('Year: {frame_time}') +
shadow_mark()
anim_save("ShootingsByYear.gif", map_with_animation)
map_with_animation
Animated plot of Philadelphia Shootings By
Year
Interactive Map of
Philadelphia Shootings
A map visualizing all the relevant information and key points
demonstrated above is shown below.
gif = st_as_sf(data.frame(x = -75.4077, y = 39.9168),
coords = c("x", "y"),
crs = 4326)
tnd = st_as_sf(data.frame(x = -75.3877, y = 39.9168),
coords = c("x", "y"),
crs = 4326)
ageDist = st_as_sf(data.frame(x = -75.3677, y = 39.9168),
coords = c("x", "y"),
crs = 4326)
distloc = st_as_sf(data.frame(x = -75.3477, y = 39.9168),
coords = c("x", "y"),
crs = 4326)
tbl = st_as_sf(data.frame(x = -75.3277, y = 39.9168),
coords = c("x", "y"),
crs = 4326)
bpl = st_as_sf(data.frame(x = -75.3077, y = 39.9168),
coords = c("x", "y"),
crs = 4326)
title1 <- tags$div(HTML('<font color = "darkred" size =5><b>Shootings in Philadelphia</b></font>'))
fl = tempfile(fileext = ".html")
saveWidget(distfig, file = fl)
philcolor <- rep("#0072B2", length(shooting_data$fatal))
philcolor[which(shooting_data$fatal == 1)] <- "#D55E00"
shootingbyyear <- "https://github.com/chinwex/STA553/raw/main/w08/ShootingsByYear.gif"
labels <- paste("Location: ",shooting_data$location,
"<br>Wound: ", shooting_data$wound,
"<br>Sex: ", shooting_data$sex,
"<br>Year: ", shooting_data$year,
"<br>Age: ", shooting_data$age)%>%
lapply(htmltools::HTML)
leaflet() %>%
setView(lng=-75.15092, lat=40.00995, zoom = 11) %>%
#addProviderTiles(providers$Esri.WorldGrayCanvas, group = "Grey")%>%
addProviderTiles(providers$CartoDB.DarkMatter, group="Dark") %>%
addProviderTiles(providers$CartoDB.DarkMatterNoLabels, group="DarkLabel") %>%
addProviderTiles(providers$Esri.NatGeoWorldMap, group="Esri") %>%
addControl(title1, position = "topright", className="map-title") %>%
## mini reference map
addMiniMap() %>%
## neighborhood boundary
addPolygons(data = phillyNeighbor,
color = 'lightgreen',
weight = 1) %>%
## plot information on the map
addCircleMarkers(data = shooting_data,
~lng,
~lat,
color = philcolor,
fillColor = ifelse(shooting_data$fatal == 1, "#ffff66", "#ff99ff"),
radius = 10,
opacity = 1,
# stroke = FALSE,
fillOpacity = 0.25,
label = ~labels,
clusterOptions = markerClusterOptions(maxClusterRadius = 40)) %>%
# Trend of crimes over the years
addCircleMarkers(data = tnd,
color = "red",
weight = 2,
label = "Trend",
stroke = FALSE,
fillOpacity = 0.95,
group = "tnd") %>%
addPopupGraphs(list(A1),
width = 450,
height = 300,
tooltip = FALSE,
group = "tnd") %>%
# age distribution within the two types of crimes
addCircleMarkers(data = ageDist,
color = "#0072B2",
weight = 2,
label = "Age Distribution",
stroke = FALSE,
fillOpacity = 0.95,
group = "ageDist") %>%
addPopupGraphs(list(fatalAge),
width = 450,
height = 300,
tooltip = FALSE,
group = "ageDist") %>%
# shooting counts by district: bubble plot
addCircleMarkers(data = distloc,
color = "purple",
weight = 2,
label = "Crimes by District",
stroke = FALSE,
fillOpacity = 0.95,
group = "distloc") %>%
leafpop:::addPopupIframes(
source = fl,
width = 450,
height = 300,
group = "distloc") %>%
# Animated shooting counts by years
addCircleMarkers(data = gif,
color = "#CC79A7",
weight = 2,
label = "Shootings by year",
stroke = FALSE,
fillOpacity = 0.95,
group = "gif") %>%
addPopupImages(shootingbyyear,
width = 450,
height = 300,
tooltip = FALSE,
group = "gif") %>%
addCircleMarkers(data = tbl,
color = "gold",
weight = 2,
label = "Summary Table",
stroke = FALSE,
fillOpacity = 0.95,
group = "tbl",
popup = htmlTable(dt)) %>%
# barplot of crime by race
addCircleMarkers(data = bpl,
color = "green",
weight = 2,
label = "Crime by Race",
stroke = FALSE,
fillOpacity = 0.95,
group = "bpl") %>%
addPopupGraphs(list(A2),
width = 450,
height = 300,
tooltip = FALSE,
group = "bpl") %>%
addLayersControl(baseGroups = c('Dark', 'DarkLabel', 'Esri'),
overlayGroups = c("Shooting Data"),
options = layersControlOptions(collapsed = TRUE)) %>%
##
browsable()
LS0tDQp0aXRsZTogIlZpc3VhbGl6aW5nIEdlb3NwYXRpYWwgSW5mb3JtYXRpb24gLSBBIENhc2UgU3R1ZHkiDQphdXRob3I6ICJFY2hlZnUgQ2hpbndlbmR1Ig0KZGF0ZTogIjIwMjQtMDMtMjciDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBmaWdfd2lkdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgZmlnX2hlaWdodDogNA0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCi8qIFRhYmxlIG9mIGNvbnRlbnQgLSBuYXZpZ2F0aW9uICovDQpkaXYjVE9DIGxpIHsNCiAgICBsaXN0LXN0eWxlOm5vbmU7DQogICAgYmFja2dyb3VuZC1jb2xvcjpsaWdodGdyYXk7DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICAgIGNvbG9yOiAjNzgwYzBjOw0KfQ0KDQoNCi8qIFRpdGxlIGZvbnRzICovDQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IGRhcmtibHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBmb250LXZhcmlhbnQtY2Fwczogbm9ybWFsOw0KfQ0KaDQuYXV0aG9yIHsgDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBkYXJrYmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQovKiBTZWN0aW9uIGhlYWRlcnMgKi8NCmgxIHsNCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDIgew0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IA0KICAgIGZvbnQtc2l6ZTogMTVweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7DQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIERlY29yYXRpb24gb2YgaHlwZXJsaW5rcyAgKi8NCg0KLyogdW52aXNpdGVkIGxpbmsgKi8NCmE6bGluayB7DQogIGNvbG9yOiBncmVlbjsNCn0NCg0KLyogdmlzaXRlZCBsaW5rICovDQphOnZpc2l0ZWQgew0KICBjb2xvcjogcHVycGxlOw0KfQ0KDQovKiBtb3VzZSBvdmVyIGxpbmsgKi8NCmE6aG92ZXIgew0KICBjb2xvcjogcmVkOw0KfQ0KDQovKiBzZWxlY3RlZCBsaW5rICovDQphOmFjdGl2ZSB7DQogIGNvbG9yOiB5ZWxsb3c7DQp9DQo8L3N0eWxlPg0KYGBgDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCm9wdGlvbnMocmVwb3MgPSBsaXN0KENSQU49Imh0dHA6Ly9jcmFuLnJzdHVkaW8uY29tLyIpKQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb3dwbG90IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQ0KICAgbGlicmFyeShjb3dwbG90KQ0KfQ0KaWYgKCFyZXF1aXJlKCJsYXRleDJleHAiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibGF0ZXgyZXhwIikNCiAgIGxpYnJhcnkobGF0ZXgyZXhwKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgIGxpYnJhcnkocGxvdGx5KQ0KfQ0KaWYgKCFyZXF1aXJlKCJnYXBtaW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiZ2FwbWluZGVyIikNCiAgIGxpYnJhcnkoZ2FwbWluZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbmciKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBuZyIpICAgICAgICAgICAgICMgSW5zdGFsbCBwbmcgcGFja2FnZQ0KICAgIGxpYnJhcnkoInBuZyIpDQp9DQppZiAoIXJlcXVpcmUoIlJDdXJsIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIpICAgICAgICAgICAgICMgSW5zdGFsbCBSQ3VybCBwYWNrYWdlDQogICAgbGlicmFyeSgiUkN1cmwiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb2xvdXJwaWNrZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImNvbG91cnBpY2tlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJjb2xvdXJwaWNrZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ2FuaW1hdGUiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdnYW5pbWF0ZSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ2FuaW1hdGUiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnaWZza2kiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdpZnNraSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnaWZza2kiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJtYWdpY2siKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hZ2ljayIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJtYWdpY2siKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnckRldmljZXMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdyRGV2aWNlcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnckRldmljZXMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJqcGVnIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJqcGVnIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImpwZWciKQ0KfQ0KaWYgKCFyZXF1aXJlKCJWR0FNIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJWR0FNIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIlZHQU0iKQ0KfQ0KaWYgKCFyZXF1aXJlKCJNQVNTIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIk1BU1MiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJubmV0IikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJubmV0IikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIm5uZXQiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjbHVzdGVyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJjbHVzdGVyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImNsdXN0ZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJzdHJpbmdyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInN0cmluZ3IiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgbGlicmFyeShzdHJpbmdyKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInRtIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInRtIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgIGxpYnJhcnkodG0pDQp9DQoNCmlmICghcmVxdWlyZSgid29yZGNsb3VkIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIndvcmRjbG91ZCIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICBsaWJyYXJ5KHdvcmRjbG91ZCkNCn0NCg0KaWYgKCFyZXF1aXJlKCJSQ3VybCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICBsaWJyYXJ5KFJDdXJsKQ0KfQ0KDQppZiAoIXJlcXVpcmUoIlhNTCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJYTUwiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgbGlicmFyeShYTUwpDQp9DQppZiAoIXJlcXVpcmUoIlNub3diYWxsQyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJTbm93YmFsbEMiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgbGlicmFyeShTbm93YmFsbEMpDQp9DQppZiAoIXJlcXVpcmUoIlJDb2xvckJyZXdlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgbGlicmFyeShSQ29sb3JCcmV3ZXIpDQp9DQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dwbG90MiIpDQp9DQppZiAoIXJlcXVpcmUoImdnYW5pbWF0ZSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dhbmltYXRlIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdnYW5pbWF0ZSIpDQp9DQppZiAoIXJlcXVpcmUoImdyYXBoaWNzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJncmFwaGljcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJncmFwaGljcyIpDQp9DQppZiAoIXJlcXVpcmUoImdncmlkZ2VzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3JpZGdlcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ3JpZGdlcyIpDQp9DQppZiAoIXJlcXVpcmUoInBseXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBseXIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgicGx5ciIpDQp9DQppZiAoIXJlcXVpcmUoImdnaXJhcGgiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdnaXJhcGgiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dpcmFwaCIpDQp9DQppZiAoIXJlcXVpcmUoImhpZ2hjaGFydGVyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJoaWdoY2hhcnRlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJoaWdoY2hhcnRlciIpDQp9DQppZiAoIXJlcXVpcmUoImZvcmVjYXN0IikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJmb3JlY2FzdCIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJmb3JlY2FzdCIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZsZXQiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZsZXQiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZmxldCIpDQp9DQppZiAoIXJlcXVpcmUoIm1hcHMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hcHMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibWFwcyIpDQp9DQppZiAoIXJlcXVpcmUoImh0bWx0b29scyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiaHRtbHRvb2xzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImh0bWx0b29scyIpDQp9DQppZiAoIXJlcXVpcmUoImh0bWx3aWRnZXRzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJodG1sd2lkZ2V0cyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJodG1sd2lkZ2V0cyIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZsZWdlbmQiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZsZWdlbmQiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZmxlZ2VuZCIpDQp9DQppZiAoIXJlcXVpcmUoImdlb2pzb25pbyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2VvanNvbmlvIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdlb2pzb25pbyIpDQp9DQppZiAoIXJlcXVpcmUoInN0cmluZ2kiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInN0cmluZ2kiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgic3RyaW5naSIpDQp9DQppZiAoIXJlcXVpcmUoIlJDb2xvckJyZXdlciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiUkNvbG9yQnJld2VyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIlJDb2xvckJyZXdlciIpDQp9DQppZiAoIXJlcXVpcmUoInRpZ3JpcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygidGlncmlzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInRpZ3JpcyIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZwb3AiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZwb3AiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZnBvcCIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZlbSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibGVhZmVtIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImxlYWZlbSIpDQp9DQppZiAoIXJlcXVpcmUoInRtYXAiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInRtYXAiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgidG1hcCIpDQp9DQppZiAoIXJlcXVpcmUoInRtYXB0b29scyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygidG1hcHRvb2xzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInRtYXB0b29scyIpDQp9DQppZiAoIXJlcXVpcmUoIndlYnNob3QyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJ3ZWJzaG90MiIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJ3ZWJzaG90MiIpDQp9DQppZiAoIXJlcXVpcmUoInNmIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJzZiIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJzZiIpDQp9DQppZiAoIXJlcXVpcmUoInRlcnJhIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJ0ZXJyYSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJ0ZXJyYSIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZwb3AiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZwb3AiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZnBvcCIpDQp9DQppZiAoIXJlcXVpcmUoIm1hcHZpZXciKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hcHZpZXciKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibWFwdmlldyIpDQp9DQppZiAoIXJlcXVpcmUoInNwRGF0YSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygic3BEYXRhIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInNwRGF0YSIpDQp9DQppZighcmVxdWlyZSgiYW5pbWF0aW9uIikpew0KICBpbnN0YWxsLnBhY2thZ2VzKCJhbmltYXRpb24iKQ0KICBsaWJyYXJ5KGFuaW1hdGlvbikNCn0NCmlmKCFyZXF1aXJlKCJnZ21hcCIpKXsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dtYXAiKQ0KICBsaWJyYXJ5KGdnbWFwKQ0KfQ0KaWYoIXJlcXVpcmUoImh0bWxUYWJsZSIpKXsNCiAgaW5zdGFsbC5wYWNrYWdlcygiaHRtbFRhYmxlIikNCiAgbGlicmFyeShodG1sVGFibGUpDQp9DQppZighcmVxdWlyZSgibWFncml0dHIiKSl7DQogIGluc3RhbGwucGFja2FnZXMoIm1hZ3JpdHRyIikNCiAgbGlicmFyeShtYWdyaXR0cikNCn0NCmlmKCFyZXF1aXJlKCJ3ZWJzaG90Iikpew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ3ZWJzaG90IikNCiAgbGlicmFyeSh3ZWJzaG90KQ0KfQ0KaWYoIXJlcXVpcmUoInZpcmlkaXMiKSl7DQogIGluc3RhbGwucGFja2FnZXMoInZpcmlkaXMiKQ0KICBsaWJyYXJ5KHZpcmlkaXMpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZlbSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibGVhZmVtIikNCmxpYnJhcnkoImxlYWZlbSIpDQp9DQppZiAoIXJlcXVpcmUoInNwRGF0YUxhcmdlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJzcERhdGFMYXJnZSIsIHJlcG9zID0gImh0dHBzOi8vZ2VvY29tcHIuci11bml2ZXJzZS5kZXYiKQ0KbGlicmFyeSgic3BEYXRhTGFyZ2UiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsZWFmbGV0LmV4dHJhcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibGVhZmxldC5leHRyYXMiKQ0KbGlicmFyeSgibGVhZmxldC5leHRyYXMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsYXR0aWNlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJsYXR0aWNlIikNCmxpYnJhcnkoImxhdHRpY2UiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJzcCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygic3AiKQ0KbGlicmFyeSgic3AiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJwYW5kZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJybGlzdCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicmxpc3QiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgicmxpc3QiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJEVCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiRFQiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiRFQiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjcm9zc3RhbGsiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImNyb3NzdGFsayIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJjcm9zc3RhbGsiKQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANCg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQojIHNob290aW5nX2RhdGEgPC0gbmEub21pdChyZWFkLmNzdihmaWxlPSJodHRwczovL2dpdGh1Yi5jb20vY2hpbndleC9TVEE1NTMvcmF3L21haW4vdzA4L3Nob290aW5ncy5jc3YiKSkNCiMgcGhpbCAgPC0gbmEub21pdChzdF9yZWFkKCJodHRwczovL2dpdGh1Yi5jb20vY2hpbndleC9TVEE1NTMvcmF3L21haW4vdzA4L3Nob290aW5ncy5nZW9qc29uIikpDQpzaG9vdGluZ19kYXRhICA8LSBuYS5vbWl0KHN0X3JlYWQoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL1NUQTU1M1ZJWi93MDgvUGhpbGx5U2hvb3RpbmdzLmdlb2pzb24iKSkNCnBoaWxseU5laWdoYm9yICA8LSBzdF9yZWFkKCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9TVEE1NTNWSVovdzA4L05laWdoYm9yaG9vZHNfUGhpbGFkZWxwaGlhLmdlb2pzb24iKQ0KcGhpbGx5ICA8LSBzdF9yZWFkKCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9TVEE1NTNWSVovdzA4L1BoaWxseU5laWdoYm9yaG9vZC1ibG9ja3MuZ2VvanNvbiIpDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NClRoaXMgZGF0YXNldCBpcyBhIGNvbWJpbmF0aW9uIG9mIGZpZWxkcyBmcm9tIE9mZmljZXIgSW52b2x2ZWQgU2hvb3RpbmdzIChPSVMpIGRhdGEgYXMgd2VsbCBhcyBmaWVsZHMgZnJvbSBjcmltaW5hbCBzaG9vdGluZyB2aWN0aW0gZGF0YSBmcm9tIHRoZSBQaGlsYWRlbHBoaWEgUG9saWNlIERlcGFydG1lbnQuIFRoZSBzaG9vdGluZyB2aWN0aW0gaW5mb3JtYXRpb24gaXMgZW50ZXJlZCBtYW51YWxseSB0byB0aGUgc291cmNlIGRhdGFiYXNlIGJ5IGV4YW1pbmluZyBpbnZlc3RpZ2F0aXZlIHJlcG9ydHMgZnJvbSBEZXRlY3RpdmVzLg0KDQpUaGVyZSBhcmUgMTUyNzcgb2JzZXJ2YXRpb25zIGFuZCAyMiB2YXJpYWJsZXMuIFNvbWUgb2YgdGhlIHZhcmlhYmxlcyBhbmQgdGhlaXIgZGVzY3JpcHRpb25zIGluY2x1ZGU6DQoNCi0gQUdFIC0gVGhlIGFnZSBvZiB0aGUgaW5kaXZpZHVhbCB3aG8gd2FzIHNob3QuDQotIFNFWCAtIFRoZSBzZXggb2YgdGhlIGluZGl2aWR1YWwgd2hvIHdhcyBzaG90Lg0KLSBSQUNFIC0gVGhlIHJhY2Ugb2YgdGhlIGluZGl2aWR1YWwgd2hvIHdhcyBzaG90Lg0KLSBDT0RFIC0gVGhlIENyaW1lIENsYXNzaWZpY2F0aW9uIENvZGUgYmFzZWQgb2ZmIG9mIHRoZSBGQkkncyBDcmltZSBSZXBvcnRpbmcgKFVDUikgc3lzdGVtLg0KMDAwMDogQWRkaXRpb25hbCBWaWN0aW07DQowMTAwIOKAkyAwMTE5OiBIb21pY2lkZTsNCjAyMDAg4oCTIDAyOTk6IFJhcGU7DQowMzAwIOKAkyAwMzk5OiBSb2JiZXJ5Ow0KMDQwMCDigJMgMDQ5OTogQWdncmF2YXRlZCBBc3NhdWx0Ow0KMzAwMCDigJMgMzkwMDogSG9zcGl0YWwgQ2FzZXM7DQotIERBVEUgLSBUaGUgZGF0ZSBvbiB3aGljaCB0aGUgc2hvb3RpbmcgdG9vayBwbGFjZQ0KLSBEQ19LRVkgLSBUaGUgdW5pcXVlIGluY2lkZW50IGlkZW50aWZpZXIuDQotIERJU1QgLSBUaGUgZGlzdHJpY3QgaW4gd2hpY2ggdGhlIHNob290aW5nIHRvb2sgcGxhY2UuDQotIEZBVEFMIC0gV2hldGhlciB0aGUgaW5kaXZpZHVhbCBkaWVkIGFzIGEgcmVzdWx0IG9mIHRoZSBzaG9vdGluZy4gMD1ObyBhbmQgMT1ZZXMuIFRoZSDigJxGQVRBTOKAnSBjb2x1bW4gaXMgZnJvbSB0aGUgY3JpbWluYWwgc2hvb3RpbmcgdmljdGltIGRhdGEgYW5kIG9ubHkgaW5kaWNhdGVzIGlmIHNvbWVvbmUgZGllZCBmcm9tIGEgY3JpbWluYWwgc2hvb3RpbmcuDQotIElOU0lERSAtIFdoZXRoZXIgdGhlIHNob290aW5nIGluY2lkZW50IHRvb2sgcGxhY2UgaW5zaWRlIGEgYnVpbGRpbmcvaG9tZSwgd2hlcmUgMD1Obywgbm90IGluc2lkZSBhbmQgMT1ZZXMsIGluc2lkZS4NCi0gTEFUSU5PIC0gV2hldGhlciBvciBub3QgdGhlIGluZGl2aWR1YWwgd2hvIHdhcyBzaG90IHdhcyBvZiBMYXRpbm8gZXRobmljaXR5Lg0KLSBMT0NBVElPTiAtIFRoZSBsb2NhdGlvbiwgZ2VuZXJhbGl6ZWQgdG8gdGhlIGJsb2NrIGxldmVsLCBvZiB0aGUgc2hvb3RpbmcuDQotIE9GRkVOREVSX0RFQ0VBU0VEIC0gV2hldGhlciB0aGUgb2ZmZW5kZXIgZGllZCBpbiBhbiBvZmZpY2VyLWludm9sdmVkIHNob290aW5nIGluY2lkZW50IChOPU5vIGFuZCBZPVllcykuDQoNClNob3duIGJlbG93IGFyZSB0aGUgZmlyc3QgNiBvYnNlcnZhdGlvbnMgZnJvbSB0aGUgZGF0YXNldDoNCg0KYGBge3J9DQprYWJsZShoZWFkKHNob290aW5nX2RhdGEpKQ0KYGBgDQoNCiMgT2JqZWN0aXZlcyBvZiB0aGUgSW50ZXJhY3RpdmUgUGxvdA0KVGhlIHNob290aW5nIGRhdGEgc2V0IGlzIG5laXRoZXIgYSBwb3B1bGF0aW9uIG5vciBhIHJhbmRvbSBzYW1wbGUgZnJvbSBhIHBvcHVsYXRpb24gaW4gUGhpbGFkZWxwaGlhLiBJdCBpcyBhIHNldCBvZiBwdWJsaWMgcmVjb3JkcyBvZiBzaG9vdGluZ3MgaW4gdGhlIG5laWdoYm9yaG9vZHMgb2YgUGhpbGFkZWxwaGlhIGZvciB0aGUgcGFzdCAxMCB5ZWFycy4gVGhpcyBkYXRhIGNvbnRhaW5zIHNvbWUgZ2VvZ3JhcGhpY2FsIGluZm9ybWF0aW9uIHN1Y2ggYXMgZGlzdHJpY3QgaW5mb3JtYXRpb24sIGJsb2NrL2xvY2F0aW9uLCBsb25naXR1ZGUsIGxhdGl0dWRlIGV0Yy4gVGhlIG1haW4gb2JqZWN0aXZlcyBhcmU6DQoNCi0gU2hvb3RpbmcgdHJlbmQgYnkgeWVhcg0KLSBBZ2UgZGVuc2l0eSBkaXN0cmlidXRpb24NCi0gQnViYmxlIHBsb3Qgb24gdGhlIG1hcA0KLSBUYWJsZSBvZiB0b3RhbCBzaG9vdGluZ3MgY2F0ZWdvcml6ZWQgdW5kZXIgUmFjZSwgU2V4IGFuZCBBZ2UgZnJvbSAyMDE1IHQwIDIwMjQNCi0gQmFyIHBsb3Qgb2Ygc2hvb3RpbmcgY291bnRzIGJ5IFJhY2UNCi0gTWFwIHNob3dpbmcgc2hvb3RpbmcgY291bnRzIGZvciBlYWNoIGRpc3RyaWN0DQoNCiMjIFRvdGFsIFNob290aW5ncyBmb3IgRGlzdHJpY3RzDQoNClNob290aW5nIGRhdGEgd2FzIGFnZ3JlZ2F0ZWQgYnkgZGlzdHJpY3QgdG8gaW5jbHVkZSBmYXRhbCwgbm9uZmF0YWwgYW5kIHRvdGFsIHNob290aW5ncyBmb3IgYWxsIGRpc3RyaWN0cy4gVGhpcyBpbmZvcm1hdGlvbiB3YXMgaWxsdXN0cmF0ZWQgb24gYSBtYXAgYW5kIHNob3duIGJlbG93LiBUaGUgY2lyY2xlIHNpemUgaXMgcHJvcG9ydGlvbmFsIHRvIHRoZSBudW1iZXIgb2Ygc2hvb3RpbmdzIGluIGEgZGlzdHJpY3QuIERpc3RyaWN0IDI1IGhhZCB0aGUgbGFyZ2VzdCBmYXRhbCBhbmQgbm9uZmF0YWwgc2hvb3RpbmdzLg0KDQpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwID0gIkEgTWFwIFNob3dpbmcgVG90YWwgU2hvb3RpbmdzIGluIFBoaWxhZGVscGhpYSBEaXN0cmljdHMifQ0Kc2hvb3RpbmdfZGF0YSRsbmcgPSBzaG9vdGluZ19kYXRhJHBvaW50X3gNCnNob290aW5nX2RhdGEkbGF0ID0gc2hvb3RpbmdfZGF0YSRwb2ludF95DQoNCmRpc3QuQ3JpbWVUYWJsZSA9IHRhYmxlKHNob290aW5nX2RhdGEkZmF0YWwsIHNob290aW5nX2RhdGEkZGlzdCkNCg0KZGlzdExvbiA9IGFnZ3JlZ2F0ZShzaG9vdGluZ19kYXRhJGxuZywgYnk9bGlzdChzaG9vdGluZ19kYXRhJGRpc3QpLCBGVU49bWVhbikNCmRpc3RMYXQgPSBhZ2dyZWdhdGUoc2hvb3RpbmdfZGF0YSRsYXQsIGJ5PWxpc3Qoc2hvb3RpbmdfZGF0YSRkaXN0KSwgRlVOPW1lYW4pDQpkaXN0TG9uTGF0ID0gbWVyZ2UoZGlzdExvbiwgZGlzdExhdCwgYnkgPSAiR3JvdXAuMSIpDQpuYW1lcyhkaXN0TG9uTGF0KSA9IGMoImRpc3RyaWN0IiwgImxuZyIsICJsYXQiKQ0KDQoNCmRpc3RDcmltZSA9IGRhdGEuZnJhbWUoZGlzdHJpY3Q9YXMubnVtZXJpYyhuYW1lcyh0YWJsZShzaG9vdGluZ19kYXRhJGRpc3QpKSksIA0KICAgICAgICAgICAgICAgICAgICAgIGZhdGFsID0gdGFibGUoc2hvb3RpbmdfZGF0YSRmYXRhbCwgc2hvb3RpbmdfZGF0YSRkaXN0KVsyLF0sDQogICAgICAgICAgICAgICAgICAgICAgbm9uZmF0YWwgPSB0YWJsZShzaG9vdGluZ19kYXRhJGZhdGFsLCBzaG9vdGluZ19kYXRhJGRpc3QpWzEsXSwNCiAgICAgICAgICAgICAgICAgICAgICB0b3RhbC5jcmltZSA9IHRhYmxlKHNob290aW5nX2RhdGEkZGlzdCkgDQogICAgICAgICAgICAgICAgICAgICAgKQ0KZGlzdENyaW1lID0gZGlzdENyaW1lWywgYygiZGlzdHJpY3QiLCAiZmF0YWwiLCAibm9uZmF0YWwiLCAidG90YWwuY3JpbWUuRnJlcSIpXQ0KY29sbmFtZXMoZGlzdENyaW1lKSA9IGMoImRpc3RyaWN0IiwgImZhdGFsIiwgIm5vbmZhdGFsIiwgInRvdGFsLmNyaW1lIikNCmRpc3RDcmltZSA9IG1lcmdlKGRpc3RMb25MYXQsIGRpc3RDcmltZSwgYnkgPSAiZGlzdHJpY3QiKQ0KDQp0aXRsZTIgPC0gdGFncyRkaXYoSFRNTCgnPGZvbnQgY29sb3IgPSAiZGFya3JlZCIgc2l6ZSA9NT48Yj5TaG9vdGluZ3MgaW4gUGhpbGFkZWxwaGlhIERpc3RyaWN0czwvYj48L2ZvbnQ+JykpDQoNCnBhbDAgPC0gY29sb3JOdW1lcmljKHBhbGV0dGUgPSB2aXJpZGlzKDI1Niwgb3B0aW9uID0gIkIiKSwgZG9tYWluID0gcmFuZ2UoZGlzdENyaW1lJHRvdGFsLmNyaW1lKSkNCmRpc3RmaWcgPC0gbGVhZmxldCgpICU+JQ0KICBzZXRWaWV3KGxuZz0tNzUuMTUyNywgbGF0PTM5Ljk3MDcsIHpvb20gPSAxMSkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRHcmF5Q2FudmFzKSAlPiUgDQogICMjIHBsb3QgdGhlIG5laWdoYm9yaG9vZCBib3VuZGFyeSBvZiBQaGlsbHkNCiAgYWRkUG9seWdvbnMoZGF0YSA9IHBoaWxseU5laWdoYm9yLA0KICAgICAgICAgICAgICBjb2xvciA9ICdsaWdodGdyZWVuJywNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkgICU+JQ0KICAgYWRkQ29udHJvbCh0aXRsZTIsIHBvc2l0aW9uID0gInRvcHJpZ2h0IiwgY2xhc3NOYW1lPSJtYXAtdGl0bGUiKSU+JQ0KICAjIw0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBkaXN0Q3JpbWUsDQogICAgICAgICAgICAgICAgICAgcmFkaXVzID0gfigodG90YWwuY3JpbWUpXigxLzMpKSwNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5wYWwwKHRvdGFsLmNyaW1lKSwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjUsDQogICAgICAgICAgICAgICAgICAgcG9wdXAgPSB+cGFzdGUoJ0Rpc3RyaWN0OicsZGlzdHJpY3QsIA0KICAgICAgICAgICAgICAgICAgICAgICc8YnI+VG90YWwgQ3JpbWU6JywgdG90YWwuY3JpbWUsIA0KICAgICAgICAgICAgICAgICAgICAgICc8YnI+RmF0YWwgQ3JpbWU6JywgZmF0YWwsDQogICAgICAgICAgICAgICAgICAgICAgJzxicj5Ob25mYXRhbCBDcmltZTonLCBub25mYXRhbCkpDQpkaXN0ZmlnDQpgYGANCg0KDQpgYGB7cn0NCnBsb3QudGhlbWUgPC0gZnVuY3Rpb24oKSB7DQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAic2FucyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwOUU3MyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDAuNSksDQogICAgIyBhZGQgYm9yZGVyIDEpDQogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICIjMDA5RTczIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gMiksDQogICAgIyBjb2xvciBiYWNrZ3JvdW5kIDIpDQogICAjIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRjBFNDQyIiksDQogICAgIyBtb2RpZnkgZ3JpZCAzKQ0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiIzU2QjRFOSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IDMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC41KSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gIGVsZW1lbnRfbGluZShjb2xvdXIgPSAiIzU2QjRFOSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjUpLA0KICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgIA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiIzU2QjRFOSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gIml0YWxpYyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiVGltZXMgTmV3IFJvbWFuIiksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiIzAwNzJCMiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gIlRpbWVzIE5ldyBSb21hbiIpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIiM1NkI0RTkiKSkNCn0NCmBgYA0KDQoNCiMjIFNob290aW5nIFRyZW5kIGJ5IFllYXINClRoZSBwbG90IGJlbG93IHNob3dzIHRoZSBzaG9vdGluZyB0cmVuZCBmcm9tIDIwMTUgdG8gMjAyNC4gVGhlcmUgd2FzIGEgc2hhcnAgaW5jcmVhc2UgaW4gdGhlIG51bWJlciBvZiBzaG9vdGluZ3MgZnJvbSAyMDE5IHRvIDIwMjAuIFRoaXMgaW5jcmVhc2Ugd2FzIG1haW50YWluZWQgYWxsIHRocm91Z2ggdGlsbCAyMDIyIGFuZCB0aGVuIHdhcyBmb2xsb3dlZCBieSBhIHNoYXJwIGRlY2xpbmUgaW4gMjAyMy4gVGhlIGluY3JlYXNlIHNlZW4gZnJvbSAyMDIwIHRvIDIwMjIgY2FuIGJlIHJlbGF0ZWQgdG8gdGhlIGNvcm9uYXZpcnVzIHBlcmlvZC4NCg0KYGBge3IgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcCA9ICJBIFRyZW5kIFBsb3Qgb2YgU2hvb3RpbmcgQ3JpbWVzIGJ5IFllYXIiLCB3YXJuaW5nPUZBTFNFfQ0KIyB0cmVuZA0KDQp5ZWFyQ3JpbWUgPSBkYXRhLmZyYW1lKHllYXI9YXMubnVtZXJpYyhuYW1lcyh0YWJsZShzaG9vdGluZ19kYXRhJHllYXIpKSksIA0KICAgICAgICAgICAgICAgICAgICAgIGZhdGFsID0gdGFibGUoc2hvb3RpbmdfZGF0YSRmYXRhbCwgc2hvb3RpbmdfZGF0YSR5ZWFyKSkNCg0KeWVhckNyaW1lID0geWVhckNyaW1lWywtMV0NCmNvbG5hbWVzKHllYXJDcmltZSkgPSBjKCJmYXRhbCIsICJ5ZWFyIiwgInRvdGFsIikNCg0KQTEgPC0gZ2dwbG90KGRhdGEgPSB5ZWFyQ3JpbWUsIGFlcyh4ID0geWVhciwgeSA9IHRvdGFsLCBncm91cCA9IGZhdGFsLCBjb2wgPSBmYXRhbCkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdG90YWwpLCBzaXplID0gMykgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiNENTVFMDAiLCAiIzAwNzJCMiIpLCBsYWJlbHM9YygiTm9uZmF0YWwiLCAiRmF0YWwiKSkrDQogIHBsb3QudGhlbWUoKSsNCiAgbGFicyh0aXRsZSA9ICJTaG9vdGluZyBDb3VudHMgYnkgWWVhciIsDQogICAgICAgeCA9ICJZZWFyIiwNCiAgICAgICB5ID0gIlNob290aW5nIENvdW50cyIpDQpBMQ0KDQpgYGANCg0KIyMgQWdlIERpc3RyaWJ1dGlvbg0KVGhlIGRlbnNpdHkgcGxvdCBiZWxvdyBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBhZ2VzIG9mIGluZGl2aWR1YWxzIHdobyB3ZXJlIHNob3QuIFRoZSBtb3N0IGNvbW1vbiBhZ2UgZm9yIHNob290aW5nIHZpY3RpbXMgd2FzIDI4LiANCg0KYGBge3IgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcCA9ICJBZ2UgRGlzdHJpYnV0aW9uIERlbnNpdHkgUGxvdCIsIHdhcm5pbmc9RkFMU0V9DQojIyAxLiBhZ2UgZGlzdHJpYnV0aW9uDQojIEJhc2ljIGRlbnNpdHkgcGxvdCBpbiBnZ3Bsb3QyDQpzaG9vdGluZ19kYXRhJGFnZSA9IGFzLm51bWVyaWMoc2hvb3RpbmdfZGF0YSRhZ2UpDQpmYXRhbEFnZSA9IGdncGxvdChkYXRhID0gc2hvb3RpbmdfZGF0YSwgYWVzKHggPSBhZ2UsIGZpbGwgPSBhcy5mYWN0b3IoZmF0YWwpKSApKw0KICAgICAgICAgICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjYpICArDQogICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0NDNzlBNyIsICIjNzJEOEZGIiksIGxhYmVscz1jKCJOb25mYXRhbCIsICJGYXRhbCIpKSsNCiAgbGFicyhmaWxsID0gIkZhdGFsIiwNCiAgICAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQWdlIikgKw0KICBwbG90LnRoZW1lKCkNCmZhdGFsQWdlDQpgYGANCiMjIFJhY2UgRGlzdHJpYnV0aW9uDQpBIGJhciBwbG90IHdhcyB1c2VkIHRvIGlsbHVzdHJhdGUgdGhlIHRvdGFsIHNob290aW5ncyBieSByYWNlLiBGb3VyIGRpZmZlcmVudCByYWNpYWwgZ3JvdXBzIHdlcmUgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGFzZXQuIFRoZXkgYXJlIEFzaWFuLCBCbGFjaywgVW5rbm93biBhbmQgV2hpdGUuIFRoZSBncm91cCB3aXRoIHRoZSBoaWdoZXN0IG51bWJlciBvZiBzaG9vdGluZyB2aWN0aW1zIHdlcmUgQmxhY2tzIHdpdGggb3ZlciAxMjAwMCByZWNvcmRzIGluIDEwIHllYXJzLg0KDQpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwID0gIkEgQmFyIFBsb3QgU2hvd2luZyBTaG9vdGluZyBEaXN0cmlidXRpb24gYnkgUmFjZSIsIHdhcm5pbmc9RkFMU0V9DQoNCg0KQTIgPC0gZ2dwbG90KGRhdGEgPSBzaG9vdGluZ19kYXRhLCBhZXMoeCA9IHJhY2UpKSArDQogIGdlb21fYmFyKGNvbG9yID0gIiM1NkI0RTkiLCBmaWxsID0gInllbGxvdyIpKw0KICBsYWJzKHggPSAiUmFjZSIsDQogICAgICAgeSA9ICJUb3RhbCBTaG9vdGluZ3MiLA0KICAgICAgIHRpdGxlID0gIlBsb3Qgb2YgVG90YWwgU2hvb3RpbmdzIEJ5IFJhY2UiKSArIA0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIkEiID0gIkFzaWFuIiwgIkIiID0gIkJsYWNrIiwgIlUiID0gIlVua25vd24iLCAiVyIgPSAiV2hpdGUiKSkgKw0KICBwbG90LnRoZW1lKCkNCkEyDQpgYGANCg0KIyMgU3VtbWFyeSBUYWJsZQ0KQSB0YWJsZSBzdW1tYXJpemluZyB0b3RhbCBzaG9vdGluZ3MgYnkgc2V4LCByYWNlLCBhZ2UgaXMgc2hvd24gYmVsb3cuIFRoZSBhdmVyYWdlIGFnZSBvZiBzaG9vdGluZyB2aWN0aW1zIHdhcyAyOCBpbiB0aGUgZWFybGllciB5ZWFycyBhbmQgdGhlbiBpbmNyZWFzZWQgdG8gMzEgbGF0ZXIuIEJsYWNrIG1hbGVzIGFyZSBtb3JlIGxpa2VseSB0byBiZSB2aWN0aW1zIG9mIHNob290aW5nIGNyaW1lcyB0aGFuIG90aGVyIGdyb3Vwcy4NCg0KYGBge3J9DQpkdCA9IGRhdGEuZnJhbWUoeWVhcj1hcy5udW1lcmljKG5hbWVzKHRhYmxlKHNob290aW5nX2RhdGEkeWVhcikpKSwgDQogICAgICAgICAgICAgICAgICAgICAgZmF0YWwgPSB0YWJsZShzaG9vdGluZ19kYXRhJGZhdGFsLCBzaG9vdGluZ19kYXRhJHllYXIpWzIsXSwNCiAgICAgICAgICAgICAgICAgICAgICBub25mYXRhbCA9IHRhYmxlKHNob290aW5nX2RhdGEkZmF0YWwsIHNob290aW5nX2RhdGEkeWVhcilbMSxdLA0KICAgICAgICAgICAgICAgICAgICAgIHRvdGFsLmNyaW1lID0gdGFibGUoc2hvb3RpbmdfZGF0YSR5ZWFyKSwNCiAgICAgICAgICAgICAgICAgQmxhY2sgPSB0YWJsZShzaG9vdGluZ19kYXRhJHJhY2UsIHNob290aW5nX2RhdGEkeWVhcilbMixdLA0KICAgICAgICAgICAgICAgIE1hbGVzID0gdGFibGUoc2hvb3RpbmdfZGF0YSRzZXgsIHNob290aW5nX2RhdGEkeWVhcilbMixdLA0KICAgICAgICAgICAgICAgIEZlbWFsZXMgPSB0YWJsZShzaG9vdGluZ19kYXRhJHNleCwgc2hvb3RpbmdfZGF0YSR5ZWFyKVsxLF0sDQogICAgICAgICAgICAgICAgYWdlID0gc2lnbmlmKHRhcHBseShzaG9vdGluZ19kYXRhJGFnZSwgc2hvb3RpbmdfZGF0YSR5ZWFyLCBtZWFuKSwgZGlnaXRzID0gMikNCiAgICAgICAgICAgICAgICAgICAgICApDQpkdCA9IGR0WywtYygxLDQsNSldDQpjb2xuYW1lcyhkdCkgPSBjKCJGYXRhbCIsICJOb25mYXRhbCIsICJCbGFjayIsICJNYWxlcyIsICJGZW1hbGVzIiwgIkFnZSIpDQpBMyA8LSBEVDo6ZGF0YXRhYmxlKGR0LCBmaWxsQ29udGFpbmVyID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1KSkNCkEzDQoNCmBgYA0KDQojIyBBbmltYXRlZCBQbG90IG9mIFNob290aW5ncyBCeSBZZWFyDQoNCmBgYHtyIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXAgPSAiQW5pbWF0ZWQgcGxvdCBvZiBQaGlsYWRlbHBoaWEgU2hvb3RpbmdzIEJ5IFllYXIifQ0Kd2hpY2hfc3RhdGUgPC0gInBlbm5zeWx2YW5pYSINCmNvdW50eV9pbmZvIDwtIG1hcF9kYXRhKCJjb3VudHkiLCByZWdpb249d2hpY2hfc3RhdGUpDQpwaGlsbHlfaW5mbyA8LSBjb3VudHlfaW5mb1tjb3VudHlfaW5mbyRzdWJyZWdpb24gPT0gInBoaWxhZGVscGhpYSIsXQ0KDQoNCmJhc2VfbWFwIDwtIGdncGxvdChkYXRhID0gcGhpbGx5X2luZm8sIG1hcHBpbmcgPSBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApKSArDQogZ2VvbV9wb2x5Z29uKGNvbG9yID0gIiMwMDlFNzMiLCBmaWxsID0gImxpZ2h0eWVsbG93IikgKw0KICBjb29yZF9xdWlja21hcCgpICsNCiAgdGhlbWVfdm9pZCgpIA0KDQptYXBfd2l0aF9kYXRhIDwtIGJhc2VfbWFwICsNCiAgZ2VvbV9wb2ludChkYXRhID0gc2hvb3RpbmdfZGF0YSwgYWVzKHggPSBsbmcsIHkgPSBsYXQsIGNvbG9yID0gZmFjdG9yKGZhdGFsKSwgZmlsbCA9IGZhY3RvcihmYXRhbCksIGdyb3VwPXllYXIpLCBzaXplID0gMiwgYWxwaGEgPSAwLjUpICArDQogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIxLCAyNCkpICsNCnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDA3MkIyIiwgIiNENTVFMDAiKSkNCg0KbWFwX3dpdGhfYW5pbWF0aW9uIDwtIG1hcF93aXRoX2RhdGEgKw0KICB0cmFuc2l0aW9uX3RpbWUoeWVhcikgKw0KICBnZ3RpdGxlKCdZZWFyOiB7ZnJhbWVfdGltZX0nKSArDQogICBzaGFkb3dfbWFyaygpDQoNCmFuaW1fc2F2ZSgiU2hvb3RpbmdzQnlZZWFyLmdpZiIsIG1hcF93aXRoX2FuaW1hdGlvbikNCm1hcF93aXRoX2FuaW1hdGlvbg0KDQpgYGANCg0KDQoNCiMgSW50ZXJhY3RpdmUgTWFwIG9mIFBoaWxhZGVscGhpYSBTaG9vdGluZ3MNCg0KQSBtYXAgdmlzdWFsaXppbmcgYWxsIHRoZSByZWxldmFudCBpbmZvcm1hdGlvbiBhbmQga2V5IHBvaW50cyBkZW1vbnN0cmF0ZWQgYWJvdmUgaXMgc2hvd24gYmVsb3cuIA0KDQpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwID0gIkEgTWFwIG9mIFBoaWxhZGVscGhpYSBTaG9vdGluZ3MifQ0KDQpnaWYgPSBzdF9hc19zZihkYXRhLmZyYW1lKHggPSAtNzUuNDA3NywgeSA9IDM5LjkxNjgpLA0KICAgICAgICAgICAgICAgIGNvb3JkcyA9IGMoIngiLCAieSIpLA0KICAgICAgICAgICAgICAgIGNycyA9IDQzMjYpDQp0bmQgPSBzdF9hc19zZihkYXRhLmZyYW1lKHggPSAtNzUuMzg3NywgeSA9IDM5LjkxNjgpLA0KICAgICAgICAgICAgICAgIGNvb3JkcyA9IGMoIngiLCAieSIpLA0KICAgICAgICAgICAgICAgIGNycyA9IDQzMjYpDQphZ2VEaXN0ID0gc3RfYXNfc2YoZGF0YS5mcmFtZSh4ID0gLTc1LjM2NzcsIHkgPSAzOS45MTY4KSwNCiAgICAgICAgICAgICAgICBjb29yZHMgPSBjKCJ4IiwgInkiKSwNCiAgICAgICAgICAgICAgICBjcnMgPSA0MzI2KQ0KZGlzdGxvYyA9IHN0X2FzX3NmKGRhdGEuZnJhbWUoeCA9IC03NS4zNDc3LCB5ID0gMzkuOTE2OCksDQogICAgICAgICAgICAgICAgY29vcmRzID0gYygieCIsICJ5IiksDQogICAgICAgICAgICAgICAgY3JzID0gNDMyNikNCnRibCA9IHN0X2FzX3NmKGRhdGEuZnJhbWUoeCA9IC03NS4zMjc3LCB5ID0gMzkuOTE2OCksDQogICAgICAgICAgICAgICAgY29vcmRzID0gYygieCIsICJ5IiksDQogICAgICAgICAgICAgICAgY3JzID0gNDMyNikNCmJwbCA9IHN0X2FzX3NmKGRhdGEuZnJhbWUoeCA9IC03NS4zMDc3LCB5ID0gMzkuOTE2OCksDQogICAgICAgICAgICAgICAgY29vcmRzID0gYygieCIsICJ5IiksDQogICAgICAgICAgICAgICAgY3JzID0gNDMyNikNCg0KdGl0bGUxIDwtIHRhZ3MkZGl2KEhUTUwoJzxmb250IGNvbG9yID0gImRhcmtyZWQiIHNpemUgPTU+PGI+U2hvb3RpbmdzIGluIFBoaWxhZGVscGhpYTwvYj48L2ZvbnQ+JykpDQoNCmZsID0gdGVtcGZpbGUoZmlsZWV4dCA9ICIuaHRtbCIpDQpzYXZlV2lkZ2V0KGRpc3RmaWcsIGZpbGUgPSBmbCkNCg0KDQpwaGlsY29sb3IgPC0gcmVwKCIjMDA3MkIyIiwgbGVuZ3RoKHNob290aW5nX2RhdGEkZmF0YWwpKQ0KcGhpbGNvbG9yW3doaWNoKHNob290aW5nX2RhdGEkZmF0YWwgPT0gMSldIDwtICIjRDU1RTAwIg0KDQpzaG9vdGluZ2J5eWVhciA8LSAiaHR0cHM6Ly9naXRodWIuY29tL2NoaW53ZXgvU1RBNTUzL3Jhdy9tYWluL3cwOC9TaG9vdGluZ3NCeVllYXIuZ2lmIg0KDQpsYWJlbHMgPC0gIHBhc3RlKCJMb2NhdGlvbjogIixzaG9vdGluZ19kYXRhJGxvY2F0aW9uLCANCiAgICAgICAgICAgICAiPGJyPldvdW5kOiAiLCBzaG9vdGluZ19kYXRhJHdvdW5kLA0KICAgICAgICAgICAgICAiPGJyPlNleDogIiwgc2hvb3RpbmdfZGF0YSRzZXgsDQogICAgICAgICAgICAgIjxicj5ZZWFyOiAiLCBzaG9vdGluZ19kYXRhJHllYXIsDQogICAgICAgICAgICAgIjxicj5BZ2U6ICIsIHNob290aW5nX2RhdGEkYWdlKSU+JSANCiAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQ0KDQoNCmxlYWZsZXQoKSAlPiUNCiAgc2V0Vmlldyhsbmc9LTc1LjE1MDkyLCBsYXQ9NDAuMDA5OTUsIHpvb20gPSAxMSkgJT4lDQogICNhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRFc3JpLldvcmxkR3JheUNhbnZhcywgZ3JvdXAgPSAiR3JleSIpJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuRGFya01hdHRlciwgZ3JvdXA9IkRhcmsiKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5EYXJrTWF0dGVyTm9MYWJlbHMsIGdyb3VwPSJEYXJrTGFiZWwiKSAlPiUgIA0KIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuTmF0R2VvV29ybGRNYXAsIGdyb3VwPSJFc3JpIikgJT4lDQogIA0KICBhZGRDb250cm9sKHRpdGxlMSwgcG9zaXRpb24gPSAidG9wcmlnaHQiLCBjbGFzc05hbWU9Im1hcC10aXRsZSIpICU+JQ0KICAjIyBtaW5pIHJlZmVyZW5jZSBtYXANCiAgYWRkTWluaU1hcCgpICU+JQ0KICAjIyBuZWlnaGJvcmhvb2QgYm91bmRhcnkNCiAgYWRkUG9seWdvbnMoZGF0YSA9IHBoaWxseU5laWdoYm9yLA0KICAgICAgICAgICAgICBjb2xvciA9ICdsaWdodGdyZWVuJywNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkgICU+JQ0KICAjIyBwbG90IGluZm9ybWF0aW9uIG9uIHRoZSBtYXANCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gc2hvb3RpbmdfZGF0YSwNCiAgICAgICAgICAgICAgICAgICAgIH5sbmcsIA0KICAgICAgICAgICAgICAgICAgICAgfmxhdCwNCiAgICAgICAgICAgIGNvbG9yID0gcGhpbGNvbG9yLA0KICAgICAgICAgICAgZmlsbENvbG9yID0gaWZlbHNlKHNob290aW5nX2RhdGEkZmF0YWwgPT0gMSwgIiNmZmZmNjYiLCAiI2ZmOTlmZiIpLA0KICAgICAgICAgICAgcmFkaXVzID0gMTAsDQogICAgICAgICAgICBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgIyBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC4yNSwNCiAgICAgICAgICAgIGxhYmVsID0gfmxhYmVscywNCiAgICAgICAgICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMobWF4Q2x1c3RlclJhZGl1cyA9IDQwKSkgJT4lDQogIA0KICAjIFRyZW5kIG9mIGNyaW1lcyBvdmVyIHRoZSB5ZWFycw0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSB0bmQsIA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJUcmVuZCIsDQogICAgICAgICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC45NSwNCiAgICAgICAgICAgICAgICAgICBncm91cCA9ICJ0bmQiKSAlPiUNCiAgYWRkUG9wdXBHcmFwaHMobGlzdChBMSksIA0KICAgICAgICAgICAgICAgICAgd2lkdGggPSA0NTAsDQogICAgICAgICAgICAgICAgICBoZWlnaHQgPSAzMDAsDQogICAgICAgICAgICAgICAgICB0b29sdGlwID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBncm91cCA9ICJ0bmQiKSAlPiUNCiAjIGFnZSBkaXN0cmlidXRpb24gd2l0aGluIHRoZSB0d28gdHlwZXMgb2YgY3JpbWVzDQogYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gYWdlRGlzdCwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwNzJCMiIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJBZ2UgRGlzdHJpYnV0aW9uIiwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjk1LA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gImFnZURpc3QiKSAlPiUNCiAgYWRkUG9wdXBHcmFwaHMobGlzdChmYXRhbEFnZSksIA0KICAgICAgICAgICAgICAgICAgd2lkdGggPSA0NTAsDQogICAgICAgICAgICAgICAgICBoZWlnaHQgPSAzMDAsDQogICAgICAgICAgICAgICAgICB0b29sdGlwID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBncm91cCA9ICJhZ2VEaXN0IikgJT4lDQogICMgc2hvb3RpbmcgY291bnRzIGJ5IGRpc3RyaWN0OiBidWJibGUgcGxvdA0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBkaXN0bG9jLCANCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJwdXJwbGUiLA0KICAgICAgICAgICAgICAgICAgIHdlaWdodCA9IDIsDQogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAiQ3JpbWVzIGJ5IERpc3RyaWN0IiwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjk1LA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gImRpc3Rsb2MiKSAlPiUNCiAgbGVhZnBvcDo6OmFkZFBvcHVwSWZyYW1lcygNCiAgICAgICAgICAgICAgICAgIHNvdXJjZSA9IGZsLA0KICAgICAgICAgICAgICAgICAgIHdpZHRoID0gNDUwLA0KICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gMzAwLA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gImRpc3Rsb2MiKSAlPiUNCiAgIyBBbmltYXRlZCBzaG9vdGluZyBjb3VudHMgYnkgeWVhcnMNCiAgIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGdpZiwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiI0NDNzlBNyIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJTaG9vdGluZ3MgYnkgeWVhciIsDQogICAgICAgICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC45NSwNCiAgICAgICAgICAgICAgICAgICBncm91cCA9ICJnaWYiKSAlPiUNCiAgYWRkUG9wdXBJbWFnZXMoc2hvb3RpbmdieXllYXIsIA0KICAgICAgICAgICAgICAgICAgd2lkdGggPSA0NTAsDQogICAgICAgICAgICAgICAgICBoZWlnaHQgPSAzMDAsDQogICAgICAgICAgICAgICAgICB0b29sdGlwID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBncm91cCA9ICJnaWYiKSAlPiUgDQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IHRibCwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ29sZCIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJTdW1tYXJ5IFRhYmxlIiwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjk1LA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gInRibCIsDQogICAgICAgICAgICAgICAgICAgcG9wdXAgPSBodG1sVGFibGUoZHQpKSAlPiUNCiAgIyBiYXJwbG90IG9mIGNyaW1lIGJ5IHJhY2UNCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gYnBsLCANCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmVlbiIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJDcmltZSBieSBSYWNlIiwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjk1LA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gImJwbCIpICU+JQ0KICBhZGRQb3B1cEdyYXBocyhsaXN0KEEyKSwgDQogICAgICAgICAgICAgICAgICB3aWR0aCA9IDQ1MCwNCiAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDMwMCwNCiAgICAgICAgICAgICAgICAgIHRvb2x0aXAgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgIGdyb3VwID0gImJwbCIpICU+JQ0KICBhZGRMYXllcnNDb250cm9sKGJhc2VHcm91cHMgPSBjKCdEYXJrJywgJ0RhcmtMYWJlbCcsICdFc3JpJyksDQogICAgICAgICAgICAgICAgICAgb3ZlcmxheUdyb3VwcyA9IGMoIlNob290aW5nIERhdGEiKSwNCiAgICAgICAgICAgICAgICAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gVFJVRSkpICU+JQ0KICAjIw0KICBicm93c2FibGUoKQ0KDQpgYGANCg0KDQoNCg0K